package com.apes.scm.rbac.service;

import com.alibaba.fastjson.JSONObject;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.OutboxEventService;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.plugin.outbox.OutboxSubscriberService;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.util.MapUtil;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.rbac.model.Menu;
import com.apes.scm.rbac.model.Operation;
import com.apes.scm.rbac.model.Post;
import com.apes.scm.rbac.model.Role;
import com.apes.scm.rbac.multiKeys.MenuOperationKey;
import com.apes.scm.rbac.repository.OperationRepository;
import com.apes.scm.rbac.repository.PostRepository;
import com.apes.scm.rbac.repository.RoleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;


/**
 * 功能：角色定义
 *
 * @author cxm
 * @create 2018-03-08 10:26
 * @desc 权限相关
 **/
@Service("roleService")
public class RoleService extends DomainService {
    @Autowired
    RoleRepository roleRepository;

    @Autowired
    OperationRepository operationRepository;

    public static final String TERMINA_MERCHANT_APP = "merchantApp";
    public static final String TERMINA_MERCHANT_SYSTEM = "merchantSystem";
    public static final String TERMINA_PLATFORM_APP = "platformApp";
    public static final String TERMINA_PLATFORM_SYSTEM = "platformSystem";
    public static final String TERMINA_SUPPLIER_SYSTEM = "supplierSystem";

    /*
     * 创建、更新
     * */
    public Role save(SimpleRequest request) {
        Role role = request.getO(Role.class);
        Set<Operation> operations = new HashSet<>();
        //原始通用的写法
//        role.getOptList().forEach(m -> {
//            MenuOperationKey mok = new MenuOperationKey();
//            mok.setMenu(Integer.parseInt(m.get("menu_id").toString()));
//            mok.setOperationId(m.get("operationId").toString());
//            operations.add(operationRepository.findOne(mok));
//        });
        /**
         * 不可通用
         *强行写死的遍历前端界面传来的操作列表(与前端界面直接对应，界面修改 此处也需开发手动更改)
         * 清洗数据
         **/
        if (role.getMerchantAppOptList() != null) {
            role.getMerchantAppOptList().forEach(m -> {
                MenuOperationKey mok = new MenuOperationKey();
                mok.setMenu(Integer.parseInt(m.get("menu_id").toString()));
                mok.setOperationId(m.get("operationId").toString());
                operations.add(operationRepository.findOne(mok));
            });
        }
        if (role.getMerchantSystemOptList() != null) {
            role.getMerchantSystemOptList().forEach(m -> {
                MenuOperationKey mok = new MenuOperationKey();
                mok.setMenu(Integer.parseInt(m.get("menu_id").toString()));
                mok.setOperationId(m.get("operationId").toString());
                operations.add(operationRepository.findOne(mok));
            });
        }
        if (role.getPlatformAppOptList() != null) {

            role.getPlatformAppOptList().forEach(m -> {
                MenuOperationKey mok = new MenuOperationKey();
                mok.setMenu(Integer.parseInt(m.get("menu_id").toString()));
                mok.setOperationId(m.get("operationId").toString());
                operations.add(operationRepository.findOne(mok));
            });
        }
        if (role.getPlatformSystemOptList() != null) {
            role.getPlatformSystemOptList().forEach(m -> {
                MenuOperationKey mok = new MenuOperationKey();
                mok.setMenu(Integer.parseInt(m.get("menu_id").toString()));
                mok.setOperationId(m.get("operationId").toString());
                operations.add(operationRepository.findOne(mok));
            });
        }

        if (role.getSupplierSystemOptList() != null) {
            role.getSupplierSystemOptList().forEach(m -> {
                MenuOperationKey mok = new MenuOperationKey();
                mok.setMenu(Integer.parseInt(m.get("menu_id").toString()));
                mok.setOperationId(m.get("operationId").toString());
                operations.add(operationRepository.findOne(mok));
            });
        }

        role.setOperations(operations);
        Role result = roleRepository.saveAndFlush(role);
//        result.setOptList(getOptList(result));
        optListRedundancy(result);
        removeMenuAuth(result);
        return result;
    }

    protected void removeMenuAuth(Role role) {
        JSONObject payload = new JSONObject();
        payload.put("id", role.getId());
        SpringManager.getBean(OutboxSubscriberService.class).commonSendRequest("aut.user.removeMenuAuth", role.getId(), payload);
    }

    @OutboxSubscriber(id = "aut.user.removeMenuAuth", name = "清缓存【本地角色权限】")
    public void removeMenuAuth(OutboxPayloadWrapper wrapper) {
        JSONObject payload = JSONObject.parseObject(wrapper.getPayload());
        UserService userService = SpringManager.getBean(UserService.class);
        Set<Post> posts = SpringManager.getBean(PostRepository.class).findAllByRole(payload.getString("id"));
        if (posts != null && !posts.isEmpty()) posts.forEach(post -> userService.removeMenuAuth(post.getId()));
    }


    /*
     * 删除
     * */
    public String delete(SimpleRequest request) {
        String id = request.get("id");
        Role role = roleRepository.findOne(id);
        removeMenuAuth(role);
        roleRepository.delete(role);
        return "删除成功！";
    }


    public Page<Role> findAll(SimpleRequest request) {
        return roleRepository.findAll(PageRequest.of(request.get("page"), request.get("size")));
    }

//    /*
//     *定义通用界面弹窗查询
//     * 转化成tree
//     * */
//    public Page<Role> findAllFormatTree(SimpleRequest request) {
//        Page<Role> rolePage = request.getO(Page.class);
//        // 添加 tree 结构
//        rolePage.getContent().stream().forEach(
//                (Role role) -> {
//                    //role.setTree(getTree(role));
//                    role.setOptList(getOptList(role));
//                }
//        );
//        return rolePage;
//    }

    private Set<Map> getOptList(Role role) {
        if (role.getOperations() == null) return null;
        Set operations = new HashSet<>();
        role.getOperations().forEach(op -> {
            Map row = MapUtil.mapper("menu_id", op.getMenu().getId(),
                    "operationId", op.getOperationId());
            operations.add(row);
        });
        return operations;
    }

    private void findParent(Menu menu, Set<Map> tree) {
        if (menu == null) return;
        try {
            if (tree.stream().filter(m -> m.get("id") == menu.getId()).findFirst().get() != null)
                return;
        } catch (Exception e) {
        }

        try {
            int childrenCount = 0;
            if (menu.getOperations() != null) childrenCount += menu.getOperations().size();
            if (menu.getChildren() != null) childrenCount += menu.getChildren().size();
            if (tree.stream().filter(m -> m.get("parent") == menu.getId()).count() != childrenCount)
                return;
        } catch (Exception e) {
        }

        Map m = MapUtil.mapper("id", menu.getId(),
                "parent", menu.getParent() != null ? menu.getParent().getId() : "",
                "data", menu.getId(),
                "label", menu.getName(),
                "sortCode", menu.getSortCode());
        tree.add(m);
        if (menu.getParent() != null) findParent(menu.getParent(), tree);
    }


    public Role findOne(String id) {
        return roleRepository.findOne(id);
    }


    /**
     * 根据终端将返回值固定格式，不通用，当终端改变时 ，需开发手动更改此处代码
     * 定义通用界面弹窗查询转化成tree
     *
     * @param request
     * @return
     */
    public Page<Role> findAllFormatTree(SimpleRequest request) {
        Page<Role> rolePage = request.getO(Page.class);
        // 添加 tree 结构
        rolePage.getContent().stream().forEach(
                (Role role) -> {
                    optListRedundancy(role);
                }
        );
        return rolePage;
    }

    /**
     * 根据终端将返回值固定格式，不通用，当终端改变时 ，需开发手动更改此处代码
     * 填充role值
     *
     * @param role
     * @return
     */
    private void optListRedundancy(Role role) {
        Map<String, Set<Map>> optListRedundancy = getOptListRedundancy(role);
        role.setMerchantAppOptList(optListRedundancy.get("maOperations"));
        role.setMerchantSystemOptList(optListRedundancy.get("msOperations"));
        role.setPlatformAppOptList(optListRedundancy.get("paOperations"));
        role.setPlatformSystemOptList(optListRedundancy.get("psOperations"));
        role.setSupplierSystemOptList(optListRedundancy.get("ssOperations"));
    }

    /**
     * 根据终端将返回值固定格式，不通用，当终端改变时 ，需开发手动更改此处代码
     * 查询时清洗数据
     *
     * @param role
     * @return map
     */
    private Map<String, Set<Map>> getOptListRedundancy(Role role) {
        if (role.getOperations() == null) {
            return null;
        }
        Map<String, Set<Map>> map = new HashMap<>(4);
        Set maOperations = new HashSet<>();
        Set msOperations = new HashSet<>();
        Set paOperations = new HashSet<>();
        Set psOperations = new HashSet<>();
        Set ssOperations = new HashSet<>();

        role.getOperations().forEach(op -> {
            Map row = MapUtil.mapper("menu_id", op.getMenu().getId(),
                    "operationId", op.getOperationId());
            Enumeration terminalType = op.getMenu().getTerminalType();
            if (terminalType != null) {
                if (TERMINA_MERCHANT_APP.equals(terminalType.getId())) {
                    maOperations.add(row);
                }
                if (TERMINA_MERCHANT_SYSTEM.equals(terminalType.getId())) {
                    msOperations.add(row);
                }
                if (TERMINA_PLATFORM_APP.equals(terminalType.getId())) {
                    paOperations.add(row);
                }
                if (TERMINA_PLATFORM_SYSTEM.equals(terminalType.getId())) {
                    psOperations.add(row);
                }
                if (TERMINA_SUPPLIER_SYSTEM.equals(terminalType.getId())) {
                    ssOperations.add(row);
                }
            }

        });
        map.put("maOperations", maOperations);
        map.put("msOperations", msOperations);
        map.put("paOperations", paOperations);
        map.put("psOperations", psOperations);
        map.put("ssOperations", ssOperations);

        return map;
    }

//
//    public Role updatePriceLimit(SimpleRequest request) {
//        Role roleid = request.getO(Role.class);
//        Role role = findOne(roleid.getId());
//        role.setPriLimitLevel(roleid.getPriLimitLevel());
//        Role result = roleRepository.saveAndFlush(role);
//        return result;
//    }


}
